package com.opennews.openplatform.familyexpenseapi.controller

import com.opennews.openplatform.familyexpenseapi.dto.account.group.SwitchAccountGroupDto
import com.opennews.openplatform.familyexpenseapi.dto.authentication.LoginDto
import com.opennews.openplatform.familyexpenseapi.dto.authentication.PasswordDto
import com.opennews.openplatform.familyexpenseapi.dto.authentication.RefreshTokenDto
import com.opennews.openplatform.familyexpenseapi.dto.authentication.RegisterDto
import com.opennews.openplatform.familyexpenseapi.service.AccountGroupService
import com.opennews.openplatform.familyexpenseapi.service.AuthenticationService
import com.opennews.openplatform.familyexpenseapi.service.UserService
import com.opennews.openplatform.myspringbootcore.common.constant.ERROR_USER_ACCOUNT_BAD_CREDENTIAL
import com.opennews.openplatform.myspringbootcore.common.constant.SERVER_UNAUTHORIZED
import com.opennews.openplatform.myspringbootcore.dto.ApiResponse
import com.opennews.openplatform.myspringbootcore.security.MyClaims
import com.opennews.openplatform.myspringbootcore.security.MyUserDetails
import com.opennews.openplatform.myspringbootcore.util.getSuccessResponse
import com.opennews.openplatform.myspringbootmvccore.extension.getRequestIpAddress
import com.opennews.openplatform.myspringbootmvccore.extension.sendErrorResponse
import com.opennews.openplatform.myspringbootmvccore.security.RequestIdentityExtractor
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import jakarta.validation.Valid
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/authentication")
class AuthenticationController(
    private val accountGroupService: AccountGroupService,
    private val authenticationService: AuthenticationService,
    private val userService: UserService,
    private val requestIdentityExtractor: RequestIdentityExtractor,
    private val request: HttpServletRequest,
    private val response: HttpServletResponse,
) {
    @GetMapping("/check-on-username")
    fun checkOnUsername(@RequestParam username: String): ResponseEntity<ApiResponse<Map<String, Any>>> {
        val result = userService.checkOnUsername(username)
        return getSuccessResponse(mapOf("usernameExists" to result))
    }

    @PostMapping("/register")
    fun register(@Valid @RequestBody data: RegisterDto): ResponseEntity<ApiResponse<Any?>> {
        accountGroupService.register(data.username, data.password, data.fullName)
        return getSuccessResponse()
    }

    @PostMapping("/unregister")
    fun unregister(@Valid @RequestBody data: PasswordDto): ResponseEntity<ApiResponse<Map<String, String>>> {
        val claims: MyClaims = requestIdentityExtractor.getClaims()
        val userId = claims.id.asString()
        val username = claims.username

        return if (userService.validatePassword(username, data.password)) {
            accountGroupService.unregister(userId)
            getSuccessResponse(mapOf("error" to ""))
        } else {
            getSuccessResponse(mapOf("error" to ERROR_USER_ACCOUNT_BAD_CREDENTIAL))
        }
    }

    @PostMapping("/login")
    fun login(@Valid @RequestBody data: LoginDto): ResponseEntity<ApiResponse<MyUserDetails>>? {
        val result = authenticationService.authenticateByCredential(
            data.username, data.password, request.getRequestIpAddress(), data.deviceInfo, data.systemInfo
        )

        return if ((result["errorCode"] as String?).isNullOrBlank()) {
            getSuccessResponse(result["myUserDetails"] as MyUserDetails)
        } else {
            response.sendErrorResponse(
                HttpStatus.UNAUTHORIZED.value(),
                SERVER_UNAUTHORIZED,
                result["errorCode"].toString(),
                request.requestURI.trim(),
            )

            null
        }
    }

    @PostMapping("/refresh-token")
    fun refreshToken(@Valid @RequestBody data: RefreshTokenDto): ResponseEntity<ApiResponse<MyUserDetails>>? {
        val result = authenticationService.refreshToken(
            data.refreshToken, request.getRequestIpAddress(), data.deviceInfo, data.systemInfo
        )

        return if ((result["errorCode"] as String?).isNullOrBlank()) {
            getSuccessResponse(result["myUserDetails"] as MyUserDetails)
        } else {
            response.sendErrorResponse(
                HttpStatus.UNAUTHORIZED.value(),
                SERVER_UNAUTHORIZED,
                result["errorCode"].toString(),
                request.requestURI.trim(),
            )

            null
        }
    }

    @PostMapping("/switch-account-group")
    fun switchAccountGroup(@Valid @RequestBody data: SwitchAccountGroupDto): ResponseEntity<ApiResponse<MyUserDetails>> {
        val claims: MyClaims = requestIdentityExtractor.getClaims()

        val result = authenticationService.switchAccountGroup(
            data.accountGroupId,
            claims.id.asString(),
            claims.username,
            request.getRequestIpAddress(),
            data.deviceInfo,
            data.systemInfo,
        )

        return getSuccessResponse(result)
    }
}
